import asyncio
import websockets
from key_mouse_api import *
import socket
import threading
from io import BytesIO
from PIL import Image
from PIL import ImageGrab
import lzma
import json
import os
import time


#from PIL.Image import frombuffer as Image_frombuffer


def getcopy():
    win32clipboard.OpenClipboard()
    copy_text = win32clipboard.GetClipboardData(win32con.CF_TEXT)
    win32clipboard.CloseClipboard()
    return copy_text


def my_action(_dict,windows):
    try:
        dic = json.loads(_dict)
        if dic['type'] == 'move':
            mouse_while(dic['x'],dic['y'])
        elif dic['type'] == 'mouse_down':
            mouse_down(dic['x'],dic['y'],dic['falg'])
        elif dic['type'] == 'mouse_up':
            mouse_up(dic['x'],dic['y'],dic['falg'])
        elif dic['type'] == 'wheel':
            scroll(dic['falg'])
        elif dic['type'] == 'click':
            click(dic['x'],dic['y'],dic['falg'])
        elif dic['type'] == 'key_up':
            key_up(dic['falg'])
        elif dic['type'] == 'key_down':
            key_down(dic['falg'])
        elif dic['type'] == 'close':
            windows.close()
    except json.JSONDecodeError:
        if '{' in _dict:
            my_action(_dict[_dict.find("{"):_dict.find("}")+1],windows)
    except Exception as e:
        # print("my_action",e)
        pass

def data_send(path,port):
    try:
        tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        tcp_server.bind((socket.gethostbyname(socket.gethostname()),port))
        tcp_server.listen(1)
        new_socket, client_addr = tcp_server.accept()
        s = open(path,'rb')
        while True:
            m = s.read(4096)
            if not m:
                break
            new_socket.send(m)
        new_socket.close()
        tcp_server.close()
        s.close()
    except Exception as e:
        # print("data_send",e)
        pass

def data_recv(messg):
    path = os.path.join('C:\\Users',os.getlogin(),'Desktop',messg['name'])
    s = open(path,'wb')
    try:
        client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        client.connect((messg['ip'][0],messg['ip'][1]))
        while True:
            recv_data = client.recv(4098)
            if not recv_data:
                break
            s.write(recv_data)
        client.close()
    except Exception as e:
        # print("data_recv",e)
        pass
    s.close()


class socket_tcp(socket.socket,threading.Thread):
    def __init__(self,IP,mdic):
        socket.socket.__init__(self,socket.AF_INET,socket.SOCK_STREAM)
        threading.Thread.__init__(self)
        self.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        self.bind((IP,mdic['port']))
        self.listen(5)
        self.daemon = True
        self.mdic = mdic
        self.dict_time = {"1":0.001,"2":0.01,"3":0.05,"4":0.1,"5":0.5,"6":1,"7":3,"8":5,"9":0}

    def run(self):
        try:
            new_socket, client_addr = self.accept()
            thr = threading.Thread(target=self.on_recv,args=(new_socket,))
            thr.daemon = True
            thr.start()
            mytime = self.dict_time[self.mdic['time']]
            mx = self.mdic['x']
            my = self.mdic['y']
            quality = self.mdic['quality']
            # print('tcp传输',mytime,quality,mx,my,client_addr)
            while True:
                try:
                    time.sleep(mytime)
                    bytejpg = win_pos_screenshots(quality,mx,my)
                    data = lzma.compress(bytejpg.getvalue())
                    new_socket.send(data)
                except lzma.LZMAError:
                    # print("LZMAError")
                    pass
                except Exception as e:
                    break
            new_socket.close()
        except Exception as e:
            # print('tcp new_sock',e)
            pass
        self.on_close()

    def on_recv(self,new_socket):
        while True:
            try:
                data = new_socket.recv(1024)
                if data:
                    my_action(data.decode('utf-8'),None)
            except Exception as e:
                # print('errer',e)
                break
        new_socket.close()
        self.on_close()

    def on_close(self):
        self.close()


class socket_udp(socket.socket,threading.Thread):
    def __init__(self,IP,mdic):
        socket.socket.__init__(self,socket.AF_INET,socket.SOCK_DGRAM)
        threading.Thread.__init__(self)
        self.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        self.bind((socket.gethostname(),mdic['port']))
        self.daemon = True
        self.mdic = mdic
        self.dict_time = {"1":0.001,"2":0.01,"3":0.05,"4":0.1,"5":0.5,"6":1,"7":3,"8":5,"9":0}

    def run(self):
        receive_data,addr = self.recvfrom(1024)
        thr = threading.Thread(target=self.on_recv)
        thr.daemon = True
        thr.start()
        mytime = self.dict_time[self.mdic['time']]
        mx = self.mdic['x']
        my = self.mdic['y']
        quality = self.mdic['quality']
        # print('udp传输',mytime,quality,mx,my,addr)
        while True:
            try:
                bytejpg = win_pos_screenshots(quality,mx,my)
                data = lzma.compress(bytejpg.getvalue())
                x = 0
                while x < len(data):
                    sedata = data[x:x+32500]
                    if sedata:
                        self.sendto(sedata,addr)
                    x += 32500
                self.sendto(b'stop',addr)
                time.sleep(mytime)
            except lzma.LZMAError:
                # print("LZMAError")
                pass
            except Exception as e:
                # print('udp on_send',e)
                break
        self.on_close()

    def on_recv(self):
        while True:
            try:
                receive_data,addr = self.recvfrom(1024)
                my_action(receive_data.decode('utf-8'),self)
            except Exception as e:
                # print('udp on_recv',e)
                break
        self.on_close()

    def on_close(self):
        self.close()


def win_pos_screenshots(quality,x,y):
    im = ImageGrab.grab()
    bytejpg = BytesIO()
    sim = im.resize((x, y), Image.ANTIALIAS)
    sim.save(bytejpg,quality=quality,format='jpeg')
    return bytejpg


async def auth_system(websocket):
    cred_text = return_msg(login=False,game=CONFNG.note)
    await websocket.send(cred_text)
    response_str = await websocket.recv()
    if json.loads(response_str)['msg'] == "登录成功":
        return True
    return False


async def send_msg(websocket,queue):
    print("连接接通",websocket)
    while True:
        recv_text = await websocket.recv()
        m_dcit = json.loads(recv_text)
        #print("执行类型:",m_dcit['type'])
        #print("执行内容:",m_dcit['msg'])
        #print("消息命令所属:",m_dcit['user'])
        #print("是否回执:",m_dcit['report'])
        try:
            #recv_text = await websocket.recv()
            #m_dcit = json.loads(recv_text)
            if m_dcit['type'] == 'input':
                await async_inputkey(m_dcit['msg'])
            elif m_dcit['type'] == 'tap':
                await async_click(m_dcit['msg']['x'],m_dcit['msg']['y'],m_dcit['msg']['fx'])
            elif m_dcit['type'] == 'dragthe':
                await async_move(m_dcit['msg']['x'],m_dcit['msg']['y'],m_dcit['msg']['x1'],m_dcit['msg']['y1'])
            elif m_dcit['type'] == 'scroll':
                await async_scroll(m_dcit['msg'])
            elif m_dcit['type'] == 'web_move':
                await async_mouse_while(m_dcit['msg']['x'],m_dcit['msg']['y'])
            elif m_dcit['type'] == 'web_mouse_up':
                await async_mouse_up(m_dcit['msg']['x'],m_dcit['msg']['y'],m_dcit['msg']['fx'])
            elif m_dcit['type'] == 'web_mouse_down':
                await async_mouse_down(m_dcit['msg']['x'],m_dcit['msg']['y'],m_dcit['msg']['fx'])
            elif m_dcit['type'] == 'web_key_up':
                await async_key_up(m_dcit['msg'])
            elif m_dcit['type'] == 'web_key_down':
                await async_key_down(m_dcit['msg'])
            elif m_dcit['type'] == 'cmd':
                await async_cmd(websocket,m_dcit)
            elif m_dcit['type'] == 'update':
                threading.Thread(target=data_recv,args=(m_dcit['msg'],)).start()
            elif m_dcit['type'] == 'inlay':
                await async_inlay(websocket,m_dcit,queue)
            elif m_dcit['type'] == 'tcp':
                IP = socket.gethostbyname(socket.gethostname())
                my_sockc_tcp = socket_tcp(IP,m_dcit['msg'])
                my_sockc_tcp.start()
                await websocket.send(return_msg(typ='tcp',msg={'ip':IP,'port':m_dcit['msg']['port'],'pos_x':m_dcit['msg']['x'],'pos_y':m_dcit['msg']['y'],'model':socket.gethostname()},vivo=m_dcit['user'],report=True))
                queue.put({"type":"user","msg":m_dcit['user']})
            elif m_dcit['type'] == 'udp':
                IP = socket.gethostbyname(socket.gethostname())
                my_sockc_udp = socket_udp(IP,m_dcit['msg'])
                my_sockc_udp.start()
                await websocket.send(return_msg(typ='udp',msg={'ip':IP,'port':m_dcit['msg']['port'],'pos_x':m_dcit['msg']['x'],'pos_y':m_dcit['msg']['y'],'model':socket.gethostname()},vivo=m_dcit['user'],report=True))
                queue.put({"type":"user","msg":m_dcit['user']})
        except Exception as e:
            # print("websocket send_msg",e)
            await websocket.send(return_msg(typ='err',msg=str(e),vivo=m_dcit['user'],report=True))


def recv_msg(websocket,windows,loop):
    root_user = None
    while True:
        data = windows.queue.get(True)
        if data['type'] == 'close':
            asyncio.run_coroutine_threadsafe(websocket(2,1002),loop)
            break
        elif data['type'] == 'webstart':
            asyncio.run_coroutine_threadsafe(websocket(2,1001) ,loop) 
            break
        elif data['type'] == 'restart':
            threading.Thread(target=windows.mythr.mystop,args=(1000,)).start()
        elif data['type'] == 'update':
            if os.path.isfile(data['msg']):
                name = os.path.basename(data['msg'])
                size = os.path.getsize(data['msg'])
                port = ret_prot()
                threading.Thread(target=data_send,args=(data['msg'],port)).start()
                data = return_msg(typ='update',vivo=root_user,report=True,msg={'name':name, 'size':size,'ip':(socket.gethostbyname(socket.gethostname()),port)})
                asyncio.run_coroutine_threadsafe(websocket(1,data) ,loop) 
        elif data['type'] == 'user':
            root_user = data['msg']
        elif data['type'] == 'err':
            break


async def async_main(windows):
    while True:
        mythr = None
        try:
            client = await websockets.connect('ws://' + CONFNG.ip, ping_interval=None)
            ret = await auth_system(client)
            if ret:
                loop = asyncio._get_running_loop()
                async def client_(n,data):
                    if n == 1:
                        await client.send(data)
                    elif n == 2:
                        await client.close(data)
                mythr = threading.Thread(target=recv_msg,args=(client_,windows,loop))
                mythr.daemon = True
                mythr.start()
                await send_msg(client,windows.queue)
        except websockets.exceptions.WebSocketException as err:
            def closethr():
                if mythr.isAlive():
                    windows.queue.put({"type":"err"})
                    time.sleep(0.5)
                    closethr()
            closethr()
            print(err)
            if err.code == 1001 or err.code == 1000:
                continue
            else:
                break
        except Exception as e:
            print(e)
        try:
            data = windows.queue.get(True,60)
            if data['type'] == 'close':
                break
        except:
            pass


